#include "ArchBloques.h"


ArchBloques::ArchBloques(){
	this->_tamBloque = 0;
}


ArchBloques::~ArchBloques(){
	this->_arch.close();
}


bool ArchBloques::crearArch(IHeader& cab, std::string nomArch){
	// Guarda el tamaño de los bloques del archivo
	this->_tamBloque = IBloque::getTamBloque();

	// Crea el archivo, si ya existe lo borra
	this->_arch.open(nomArch.c_str(), std::fstream::out | std::fstream::in |
			std::fstream::trunc | std::fstream::binary);

	// Chequea si se pudo crear el archivo
	if (this->_arch.fail()) return false;

	// Inicializa la cabecera del archivo
	int pos = guardar(cab, 0);

	// Se chequea si la cabecera se guardó bien
	if (pos == 0) return true;
	else return false;
}


bool ArchBloques::abrirArch(IHeader& cab, std::string nomArch){
	// Guarda el tamaño de los bloques del archivo
	this->_tamBloque = IBloque::getTamBloque();

	// Trata de abrir el archivo
	this->_arch.open(nomArch.c_str(), std::fstream::in | std::fstream::out | std::fstream::binary);

	if (this->_arch.fail()) return false;

	// Lee la cabecera del archivo
	bool res = this->leer(cab, 0);
	return res;
}


// No chequea que la posicion sea valida
int ArchBloques::guardar(IBloque& b, int pos){

	// Los parentesis inicializan el bloque de memoria en cero
	char* temp = new char[this->_tamBloque]();
	b.serialize(temp);

	// Si es "-1" inserta al final del archivo
	if (pos == -1){
		this->_arch.seekp(0, std::fstream::end);

		// Asi se calcula el nro de bloque donde se inserta
		pos = this->_arch.tellp() / this->_tamBloque;

	} else {
		// Inserta en una posicion dada
		int offset = pos * this->_tamBloque;
		this->_arch.seekp(offset, std::fstream::beg);
	}

	this->_arch.write(temp, this->_tamBloque);

	delete[] temp;

	// Chequeo de error
	if (this->_arch.bad())
		return -1;
	else
		return pos; // Esta fue la posicion donde se inserto el bloque
}


// Agregar chequeo de errores (que son muchos)
bool ArchBloques::leer(IBloque& b, int pos){

	// Los parentesis inicializan el bloque de memoria en cero
	char* temp = new char[this->_tamBloque]();
	int offset = pos * this->_tamBloque;

	this->_arch.seekg(offset);
	this->_arch.read(temp, this->_tamBloque);
	unsigned int cantLeida = this->_arch.gcount();

	b.deSerialize(temp);
	delete[] temp;

	if (this->_tamBloque != cantLeida) return false;
	else return true;
}


bool ArchBloques::is_open() const{
	return this->_arch.is_open();
}


void ArchBloques::cerrar(){
	this->_arch.close();
}
